#include "player.h"

#include "playercontrols.h"
#include "playlistmodel.h"
#include "histogramwidget.h"

#include <QtWidgets>
#include <QVideoProbe>
#include <QMediaMetaData>
//#include <QTime>
#include <QDebug>

MediaPlayer::MediaPlayer(QWidget *parent) :
    QWidget(parent),
    videoWidget(0),
    coverLabel(0),
    slider(0)
{
    player = new QMediaPlayer(this);
    playlist = new QMediaPlaylist();
    player->setPlaylist(playlist);

    connect(player,SIGNAL(durationChanged(qint64)),SLOT(durationChanged(qint64)));
    connect(player,SIGNAL(positionChanged(qint64)),SLOT(positionChanged(qint64)));
    connect(player,SIGNAL(metaDataChanged()),SLOT(metaDataChanged()));
    connect(playlist,SIGNAL(currentIndexChanged(int)),SLOT(playListPositionChanged(int)));
    connect(player,SIGNAL(bufferStatusChanged(int)),SLOT(bufferingProgress(int)));
    connect(player,SIGNAL(videoAvailableChanged(bool)),this,SLOT(videoAvailableChanged(bool)));
    connect(player,SIGNAL(error(QMediaPlayer::Error)),this,SLOT(displayErrorMessage()));

    videoWidget = new VideoWidget(this);
    player->setVideoOutput(videoWidget);

    playlistModel = new PlaylistModel(this);
    playlistModel->setPlaylist(playlist);

    playlistView = new QListView(this);
    playlistView->setModel(playlistModel);
    playlistView->setCurrentIndex(playlistModel->index(playlist->currentIndex(), 0));

    connect(playlistView,SIGNAL(activated(QModelIndex))
            ,this, SLOT(jump(QModelIndex)));

    slider = new QSlider(Qt::Horizontal);
    slider->setRange(0, player->duration() / 1000);

    labelDuration = new QLabel(this);
    connect(slider,SIGNAL(sliderMoved(int)),this,SLOT(seek(int)));

    labelHistogram = new QLabel(this);
    labelHistogram->setText("Histogram");
    histogram = new HistogramWidget(this);
    QHBoxLayout *histogramLayout = new QHBoxLayout;
    histogramLayout->addWidget(labelHistogram);
    histogramLayout->addWidget(histogram, 1);

    probe = new QVideoProbe(this);
    connect(probe,SIGNAL(videoFrameProbed(QVideoFrame))
            ,histogram,SLOT(processFrame(QVideoFrame)));

    QPushButton *openButton = new QPushButton(tr("Open"), this);

    connect(openButton,SIGNAL(clicked()),this,SLOT(open()));

    PlayerControls *controls = new PlayerControls(this);
    controls->setState(player->state());
    controls->setVolume(player->volume());
    controls->setMuted(controls->isMuted());

    connect(controls,SIGNAL(play()),player,SLOT(play()));
    connect(controls,SIGNAL(pause()),player,SLOT(pause()));
    connect(controls,SIGNAL(stop()),player,SLOT(stop()));
    connect(controls,SIGNAL(next()),playlist,SLOT(next()));
    //connect(controls,SIGNAL(previous()),playlist,SLOT(previous()));
    connect(controls,SIGNAL(previous()),this,SLOT(previousClicked()));
    connect(controls,SIGNAL(changedVolume(int)),player,SLOT(setVolume(int)));
    connect(controls,SIGNAL(changeMutting(bool)),player,SLOT(setMuted(bool)));
    connect(controls,SIGNAL(changeRate(qreal)),player,SLOT(setPlaybackRate(qreal)));

    connect(controls, SIGNAL(stop()), videoWidget,SLOT(update()));

    connect(player,SIGNAL(stateChanged(QMediaPlayer::State)),
            controls,SLOT(setState(QMediaPlayer::State)));
    connect(player,SIGNAL(volumeChanged(int)),
            controls,SLOT(setVolume(int)));
    connect(player,SIGNAL(mutedChanged(bool)),
            controls,SLOT(setMuted(bool)));

    fullScreenButton = new QPushButton(tr("FullScreen"), this);
    fullScreenButton->setCheckable(true);
   /* connect(fullScreenButton,SIGNAL(clicked(bool)),
            videoWidget,SLOT(setFullScreen(bool)));*/


    QBoxLayout *displayLayout = new QHBoxLayout;
    displayLayout->addWidget(videoWidget,2);
    displayLayout->addWidget(playlistView);

    QBoxLayout *controlsLayout = new QHBoxLayout;
    controlsLayout->setMargin(0);
    controlsLayout->addWidget(openButton);
    controlsLayout->addStretch(1);
    controlsLayout->addWidget(controls);
    controlsLayout->addStretch(1);
    controlsLayout->addWidget(fullScreenButton);

    QBoxLayout *layout = new QVBoxLayout;
    layout->addLayout(displayLayout);
    QHBoxLayout *hLayout = new QHBoxLayout;
    hLayout->addWidget(slider);
    hLayout->addWidget(labelDuration);
    layout->addLayout(hLayout);
    layout->addLayout(controlsLayout);
    layout->addLayout(histogramLayout);

    setLayout(layout);

    if (!player->isAvailable()) {
        QMessageBox::warning(this,tr("Service not available"),
                             tr("The QMediaPlayer object does "
                                "not have a vaild service.\n"
                                "Please check the media service plugins are installed."));
        controls->setEnabled(false);
        playlistView->setEnabled(false);
        openButton->setEnabled(false);

        fullScreenButton->setEnabled(false);
    }
    metaDataChanged();

    QStringList arguments = qApp->arguments();
    arguments.removeAt(0);
    addToPlaylist(arguments);
}

MediaPlayer::~MediaPlayer()
{
}

void MediaPlayer::open()
{
    qDebug() << "open button clicked... ";
    QStringList fileNames = QFileDialog::getOpenFileNames(this, "Open Files");
    addToPlaylist(fileNames);
    //qDebug() << "open button clicked... ";
}

void MediaPlayer::durationChanged(qint64 duration)
{
    this->duration = duration/1000;
    slider->setMaximum(duration/1000);
}

void MediaPlayer::positionChanged(qint64 progress)
{
    if (!slider->isSliderDown()) {
        slider->setValue(progress/1000);
    }
    updateDurationInfo(progress/1000);
}

void MediaPlayer::metaDataChanged()
{
    if (player->isMetaDataAvailable()) {
        setTrackInfo(QString("%1 - %2")
                     .arg(player->metaData(QMediaMetaData::AlbumArtist).toString())
                     .arg(player->metaData(QMediaMetaData::Title).toString()));

        if (coverLabel) {
            QUrl url = player->metaData(QMediaMetaData::CoverArtUrlLarge).value<QUrl>();

            coverLabel->setPixmap(!url.isEmpty()
                                  ? QPixmap(url.toString())
                                  : QPixmap());
        }
    }
}

void MediaPlayer::previousClicked()
{
    // Go to previous track if we are within the first 5 seconds of playback
    // Otherwise, seek to the beginning
    if (player->position() <= 5000)
        playlist->previous();
    else
        player->setPosition(0);
}

void MediaPlayer::seek(int seconds)
{
    player->setPosition(seconds * 1000);
}

void MediaPlayer::jump(const QModelIndex &index)
{
    if (index.isValid()) {
        playlist->setCurrentIndex(index.row());
        player->play();
    }
}

void MediaPlayer::playListPositionChanged(int currentItem)
{
    playlistView->setCurrentIndex(playlistModel->index(currentItem, 0));
}

void MediaPlayer::statusChanged(QMediaPlayer::MediaStatus status)
{
    handleCursor(status);

    // handle status message
    switch (status) {
    case QMediaPlayer::UnknownMediaStatus:
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::LoadedMedia:
    case QMediaPlayer::BufferingMedia:
    case QMediaPlayer::BufferedMedia:
        setStatusInfo(QString());
        break;
    case QMediaPlayer::LoadingMedia:
        setStatusInfo(tr("Loading... "));
        break;
    case QMediaPlayer::StalledMedia:
        setStatusInfo(tr("Media Stalled."));
        break;
    case QMediaPlayer::InvalidMedia:
        displayErrorMessage();
        break;
    }
}

void MediaPlayer::bufferingProgress(int progress)
{
    setStatusInfo(tr("Buffering %4%").arg(progress));
}

void MediaPlayer::videoAvailableChanged(bool available)
{
    if (!available) {
        disconnect(fullScreenButton, SIGNAL(clicked()),
                   videoWidget, SLOT(setFullScreen(bool)));
        disconnect(videoWidget, SIGNAL(fullScreenChanged(bool)),
                   fullScreenButton, SLOT(setChecked(bool)));
        videoWidget->setFullScreen(false);
    }
    else {
        connect(fullScreenButton, SIGNAL(clicked()),
                   videoWidget, SLOT(setFullScreen(bool)));
        connect(videoWidget, SIGNAL(fullScreenChanged(bool)),
                   fullScreenButton, SLOT(setChecked(bool)));

        if (fullScreenButton->isChecked())
            videoWidget->setFullScreen(true);
    }
}

void MediaPlayer::displayErrorMessage()
{
    setStatusInfo(player->errorString());
}

void MediaPlayer::addToPlaylist(const QStringList &fileNames)
{
    foreach (QString const &argument, fileNames) {
        QFileInfo fileInfo(argument);
        if (fileInfo.exists()) {
            QUrl url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
            if (fileInfo.suffix().toLower() == QLatin1String("m3u"))
            {
                playlist->addMedia(url);
            }
            else {
                QUrl url(argument);
                if (url.isValid())
                    playlist->addMedia(url);
            }
        }
    }
}

void MediaPlayer::setTrackInfo(const QString &info)
{
    trackInfo = info;
    if (!statusInfo.isEmpty()) {
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    }
    else {
        setWindowTitle(trackInfo);
    }
}

void MediaPlayer::setStatusInfo(const QString &info)
{
    statusInfo = info;
    if (!statusInfo.isEmpty()) {
        setWindowTitle(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    }
    else {
        setWindowTitle(trackInfo);
    }
}

void MediaPlayer::handleCursor(QMediaPlayer::MediaStatus /*status*/)
{

}

void MediaPlayer::updateDurationInfo(qint64 currentInfo)
{
    QString tStr(tr("nothing"));
    /*if (currentInfo || duration) {
        QTime currentTime((currentInfo/3600)%60
                          , (currentInfo/60)%60
                          , currentInfo%60
                          , (currentInfo*1000)%1000);
        QTime totalTime((duration/3600))
    }*/
    labelDuration->setText(tStr);
}
